local Class = require("Core.Class")
local LuaBehaviour = require("Core.LuaBehaviour")
local EventManager = require("Game.Manager.EventManager")
local ResManager = require("Game.Manager.ResManager")
local UnityUtils = require("Game.Util.UnityUtils")
local Coroutine = require("Core.Coroutine")
local GameManager = require("Game.Manager.GameManager")

--- @class PlayerBase
local PlayerBase = Class("PlayerBase", LuaBehaviour)

------ Unity生命周期函数 ------
function PlayerBase:__init()
    -- 常量
    self.ATTACK_WAIT_TIME = 0.5 --攻击间隔时间
    self.IS_MOVING_ID = CSE.Animator.StringToHash('IsMoving') -- '正在移动'动画HashID
    self.IS_BIRTH_ID = CSE.Animator.StringToHash('IsBirth')

    -- 基本属性
    self.playerIndex = 0
    self.lifeNum = 3
    self.moveSpeed = 150

    -- 当前状态
    self.currentIsDie = false
    self.currentIsAttack = false
    self.currentIsInvincible = false
    self.currentIsCanMoving = false
    self.currentSpeed = CSE.Vector2(0, 0)
    self.currentDir = CSE.Vector3(0, 0, 0)

    -- 当前是否改变方向
    self.isChangeDir = false

    -- 计算器
    self.attackTimer = 0.0

    -- 初始化组件
    self.anim = self.gameObject:GetComponent('Animator')
    self.rb = self.gameObject:GetComponent('Rigidbody2D')
    self.shieldObject = self.transform:Find('Shield').gameObject

    -- 按键设置
    self:InitPlayerInputKeyCode()

    -- 所有通过事件管理器管理的事件函数
    self.OnPlayerBirth = nil
    self.OnPlayerResurgence = nil

    -- 添加事件
    self:AddListeners()
end

function PlayerBase:OnDestroy()
    -- 移除事件
    self:RemoveListeners()
end

function PlayerBase:Update()
    if self.currentIsDie or not self.currentIsCanMoving then
        -- 当前状态如果死亡, 就不进行下列操作
        return
    end

    self:GetPlayerInput()
    self:SetAnimation()
    self:SetPlayerDir()
    self:PlayerAttack()
end

function PlayerBase:FixedUpdate()
    if self.currentIsDie or not self.currentIsCanMoving then
        -- 当前状态如果死亡, 就不进行下列操作
        return
    end

    self:Movement()
end

function PlayerBase:OnTriggerEnter2D(other)
    if other:CompareTag('EmenyBullet') then
        -- 如果当前无敌
        if self.currentIsInvincible then
            return
        end

        ResManager.LoadGameObject('Assets/GameRes/Prefabs/Player/Explode.prefab', self.transform.position, CSE.Quaternion.identity, function ()
            -- 初始化爆炸 -- 什么也不做
        end)

        self.lifeNum = self.lifeNum - 1
        if self.lifeNum > 0 then
            -- 复活
            self.currentIsCanMoving = false
            self.anim:SetBool(self.IS_BIRTH_ID, false)
            local playerBirthPoint = require('Game.LevelMapItemPositionTable.PlayerBirthPoint')
            self.transform.position = CSE.Vector3(playerBirthPoint[self.playerIndex][1], playerBirthPoint[self.playerIndex][2], 0)

            EventManager:Fire('PlayerResurgence', self.playerIndex)
        else
            if GameManager.currentGameMode == 1 then
                EventManager:Fire('GameOver')
            else
                -- 待定
            end
            CSE.Object.Destroy(self.gameObject)
        end
    end
end

function PlayerBase:OnCollisionEnter2D(other)
    if other.collider.tag == 'Emeny' then
        -- 如果当前无敌
        if self.currentIsInvincible then
            return
        end

        ResManager.LoadGameObject('Assets/GameRes/Prefabs/Player/Explode.prefab', self.transform.position, CSE.Quaternion.identity, function ()
            -- 初始化爆炸 -- 什么也不做
        end)

        self.lifeNum = self.lifeNum - 1
        if self.lifeNum > 0 then
            -- 复活
            self.currentIsCanMoving = false
            self.anim:SetBool(self.IS_BIRTH_ID, false)
            local playerBirthPoint = require('Game.LevelMapItemPositionTable.PlayerBirthPoint')
            self.transform.position = CSE.Vector3(playerBirthPoint[self.playerIndex][1], playerBirthPoint[self.playerIndex][2], 0)

            EventManager:Fire('PlayerResurgence', self.playerIndex)
        else
            if GameManager.currentGameMode == 1 then
                EventManager:Fire('GameOver')
            else
                -- 待定
            end
            CSE.Object.Destroy(self.gameObject)
        end
    end
end

------ 自定义函数 ------
function PlayerBase:InitPlayerInputKeyCode()
    self.UpMoveKeyCode      = nil
    self.DownMoveKeyCode    = nil
    self.LeftMoveKeyCode    = nil
    self.RightMoveKeyCode   = nil
    self.AttackKeyCode      = nil
end

function PlayerBase:AddListeners()
    self:AddPlayerBirthListener()
    self:AddPlayerResurgenceListener()
end

function PlayerBase:RemoveListeners()
    EventManager:RemoveListener('PlayerBirth', self.OnPlayerBirth)
    EventManager:RemoveListener('PlayerResurgence', self.OnPlayerResurgence)
end

function PlayerBase:GetPlayerInput()
    -- 获取玩家移动输入
    if CSE.Input.GetKey(self.UpMoveKeyCode) then
        self.isChangeDir = self.currentDir.z ~= 0
        self.currentDir:Set(0, 0, 0)
        self.currentSpeed:Set(0, 1)
    elseif CSE.Input.GetKey(self.DownMoveKeyCode) then
        self.isChangeDir = self.currentDir.z ~= 180
        self.currentDir:Set(0, 0, 180)
        self.currentSpeed:Set(0, -1)
    elseif CSE.Input.GetKey(self.LeftMoveKeyCode) then
        self.isChangeDir = self.currentDir.z ~= 90
        self.currentDir:Set(0, 0, 90)
        self.currentSpeed:Set(-1, 0)
    elseif CSE.Input.GetKey(self.RightMoveKeyCode) then
        self.isChangeDir = self.currentDir.z ~= 270
        self.currentDir:Set(0, 0, 270)
        self.currentSpeed:Set(1, 0)
    else
        self.isChangeDir = false
        self.currentSpeed:Set(0, 0)
    end

    -- 获取玩家攻击输入
    self.attackTimer = self.attackTimer + CSE.Time.deltaTime
    if self.attackTimer > self.ATTACK_WAIT_TIME and CSE.Input.GetKeyDown(self.AttackKeyCode) then
        self.attackTimer = 0.0
        self.currentIsAttack = true
    end
end

function PlayerBase:SetAnimation()
    self.anim:SetBool('IsMoving', not self.currentSpeed:Equals(CSE.Vector2.zero))
end

function PlayerBase:SetPlayerDir()
    if self.isChangeDir then
        self:MobileAdsorption()
    end
    self.transform.localEulerAngles = self.currentDir
end

function PlayerBase:MobileAdsorption()
    local pos = CSE.Vector3(self.transform.position.x, self.transform.position.y, self.transform.position.z)

    local _, posModfX = math.modf(self.transform.position.x)
    if posModfX >= 0.65 then
        pos.x = math.ceil(pos.x)
    elseif posModfX <= 0.35 then
        pos.x = math.floor(pos.x)
    end

    local _, posModfY = math.modf(self.transform.position.y)
    if posModfY >= 0.65 then
        pos.y = math.ceil(pos.y)
    elseif posModfY <= 0.35 then
        pos.y = math.floor(pos.y)
    end

    self.transform.position = pos
end

function PlayerBase:PlayerAttack()
    if self.currentIsAttack then
        self.currentIsAttack = false

        ResManager.LoadGameObject('Assets/GameRes/Prefabs/Bullet/PlayerBullet.prefab',
            self.transform.position + self.transform.up * 0.95, CSE.Quaternion.Euler(0, 0, self.currentDir.z),
            function (obj)
                -- TODO : 初始化子弹
        end) 
    end
end

function PlayerBase:Movement()
    self.rb.velocity = self.currentSpeed * (self.moveSpeed * CSE.Time.fixedDeltaTime);
end

function PlayerBase:ShowShield()
    self.currentIsInvincible = true
    self.shieldObject:SetActive(true)
end

function PlayerBase:HideShield()
    self.currentIsInvincible = false
    self.shieldObject:SetActive(false)
end

-------- 事件添加/响应 ---------
function PlayerBase:AddPlayerBirthListener()
    self.OnPlayerBirth = function (playerIndex)
        if playerIndex ~= self.playerIndex then
            return
        end

        self:ShowShield()
        local waitShieldEnd = Coroutine.Create(bind(UnityUtils.WaitFormSecond), 1, function ()
            self.currentIsCanMoving = true
            self.anim:SetBool(self.IS_BIRTH_ID, true)
            self:HideShield()
        end)
        self.host:StartCoroutine(waitShieldEnd)
    end
    EventManager:AddListener('PlayerBirth', self.OnPlayerBirth)
end

function PlayerBase:AddPlayerResurgenceListener()
    self.OnPlayerResurgence = function (playerIndex)
        if playerIndex ~= self.playerIndex then
            return
        end

        self:ShowShield()
        local waitShieldEnd = Coroutine.Create(bind(UnityUtils.WaitFormSecond), 0.5, function ()
            self.currentIsCanMoving = true
            self.anim:SetBool(self.IS_BIRTH_ID, true)
            self:HideShield()
        end)
        self.host:StartCoroutine(waitShieldEnd)
    end
    EventManager:AddListener('PlayerResurgence', self.OnPlayerResurgence)
end

return PlayerBase